package dj.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import dj.Constant;
import dj.dao.BaseDao;
import dj.model.FriendGroup;
import dj.model.Menu;
import dj.model.MenuAuth;
import dj.model.SysRoleMembers;
import dj.model.Tuser;
import dj.model.UserExtend;
import dj.pageModel.Puser;
import dj.pageModel.TreeNode;
import dj.service.SysRoleService;
import dj.service.UserService;
import dj.utils.StringUtils;

@Service("userService")
public class UserServiceImpl implements UserService {
	/**
	 * Logger for this class
	 */
	private static final Logger logger = Logger.getLogger(UserServiceImpl.class);

	private BaseDao<Tuser> userDao;

	private BaseDao<UserExtend> extendDao;

	private BaseDao<Menu> menuDao;

	private BaseDao<MenuAuth> menuAuthDao;

	private SysRoleService sysRoleService;

	public BaseDao<Tuser> getUserDao() {
		return userDao;
	}

	@Autowired
	public void setUserDao(BaseDao<Tuser> userDao) {
		this.userDao = userDao;
	}

	public BaseDao<UserExtend> getExtendDao() {
		return extendDao;
	}

	@Autowired
	public void setExtendDao(BaseDao<UserExtend> extendDao) {
		this.extendDao = extendDao;
	}

	public BaseDao<Menu> getMenuDao() {
		return menuDao;
	}

	@Autowired
	public void setMenuDao(BaseDao<Menu> menuDao) {
		this.menuDao = menuDao;
	}

	public BaseDao<MenuAuth> getMenuAuthDao() {
		return menuAuthDao;
	}

	@Autowired
	public void setMenuAuthDao(BaseDao<MenuAuth> menuAuthDao) {
		this.menuAuthDao = menuAuthDao;
	}

	public SysRoleService getSysRoleService() {
		return sysRoleService;
	}

	@Autowired
	public void setSysRoleService(SysRoleService sysRoleService) {
		this.sysRoleService = sysRoleService;
	}

	public void save(Puser puser) {
		try {
			//登录人
			Puser loginUser = null;
			try {
				loginUser = (Puser) ServletActionContext.getRequest().getSession().getAttribute(Constant.USER_SESSION);
			} catch (Exception e) {
			}
			
			Tuser user = new Tuser();
			BeanUtils.copyProperties(puser, user);
			String pwd = StringUtils.encrypt(user.getPwd()); // 密码加密
			user.setPwd(pwd);
			user.setId(UUID.randomUUID().toString());
			user.setCreateDate(new Date());
			user.setUserState(Constant.STATE_OPEN);
			//登录人员是数据管理员，并且添加的是企业用户，则把该企业添加到该数据管理员下面
			if (!"admin".equals(user.getName()) && Constant.USERTYPE_COMPANY.equals(user.getUserType()) && null != loginUser && sysRoleService.isSysRole(loginUser.getId(), Constant.SYSROLE_MEMBER_TYPE_USER, "数据管理员")) {
				user.setParentid(loginUser.getId());
			}
			userDao.save(user);
			// 扩展属性
			UserExtend ux = new UserExtend();
			BeanUtils.copyProperties(puser.getPuserExtend(), ux);
			ux.setId(UUID.randomUUID().toString());
			ux.setTuser(user);
			ux.setIconcls("app/user/icons/cat.png");
			// 将扩展属性放到用户下
			user.getUserExtends().add(ux);
			saveOrUpdateExtend(ux);
			// 系统角色，暂时自动添加
			if(!"admin".equals(user.getName())) {
				SysRoleMembers srm = new SysRoleMembers();
				srm.setId(UUID.randomUUID().toString());
				srm.setMemberid(user.getId());
				srm.setType(Constant.SYSROLE_MEMBER_TYPE_USER);
				if (Constant.USERTYPE_USER.equals(user.getUserType())) {
					srm.setSysRoles(sysRoleService.getSysRoleByName("数据管理员"));
				} else if (Constant.USERTYPE_COMPANY.equals(user.getUserType())) {
					srm.setSysRoles(sysRoleService.getSysRoleByName("企业数据员"));
				}
				sysRoleService.saveSysRoleMember(srm);
			}

			// 将公共组赋给注册用户
			List<FriendGroup> fgls = new ArrayList<FriendGroup>(Constant.COMMON_FRIENDGROUP);
			Constant.FRIENDGROUP_USER_KEY_MAP.put(user.getId(), fgls);
			// 菜单
			String hql = "from Menu where defaultMenu like:dMenu";
			Map<String, Object> params = new LinkedHashMap<String, Object>();
			params.put("dMenu", "%" + user.getUserType() + "%");
			List<Menu> menus = menuDao.find(hql, params);
			if (null != menus && menus.size() > 0) {
				for (Menu menu : menus) {
					setMenuToUser(user, menus, menu);
				}
			}

			// 更新内存
			setUser(user);
		} catch (BeansException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 新用户赋予菜单权限
	 * 
	 * @param user
	 * @param menus
	 * @param menu
	 */
	public void setMenuToUser(Tuser user, List<Menu> menus, Menu menu) {
		MenuAuth ma = new MenuAuth();
		ma.setId(UUID.randomUUID().toString());
		ma.setMenu(menu);
		ma.setMemberid(user.getId());
		menuAuthDao.save(ma);
		Menu parentMenu = menu.getMenu();
		if (null != parentMenu) {
			if (null != menus) {
				// 递归添加父菜单，如果list中没有，则自动添加，如果有则继续
				if (!menus.contains(parentMenu)) {
					setMenuToUser(user, menus, parentMenu);
				}
			}
		}
	}

	public void delete(Tuser user) {
		if (user.getUserExtends().size() > 0) {
			extendDao.delete(user.getUserExtends().iterator().next());
		}
		userDao.delete(user);
		deleteMemory(user);
	}

	public void deleteMemory(Tuser user) {
		if (!Constant.GET_USER_FROM_DB) {
			Constant.USER_ID_KEY_MAP.remove(user.getId());
			Constant.USER_NAME_KEY_MAP.remove(user.getName());
		}
	}

	public long getUserNum(Map<String, Object> params, Map<String, String> conditions) {
		Long userNum = null;
		Map<String, Object> vparams = new HashMap<String, Object>();
		String hql = "select count(u) from Tuser u, SysRoles sr, SysRoleMembers srm ";
		String condition = "";
		boolean searchExt = false;
		if (null != params && params.size() > 0) {
			for (String key : params.keySet()) {
				String valueKey = key.substring(key.indexOf(".") + 1);
				condition += " and " + key + " " + conditions.get(key) + ":" + valueKey;
				vparams.put(valueKey, params.get(key));
				// 有扩展信息查询
				if (!searchExt && key.indexOf("ue.") > -1) {
					hql += ", UserExtend ue";
					searchExt = true;
				}
			}
			hql += " where 1=1 ";
			if (searchExt) {
				condition += " and u.id = ue.tuser";
			}
			hql += condition + " and u.name <> 'admin' and srm.memberid=u.id and srm.sysRoles=sr.id";
			userNum = userDao.getCount(hql, vparams);
		} else {
			hql += " where u.name <> 'admin' and srm.memberid=u.id and srm.sysRoles=sr.id";
			userNum = userDao.getCount(hql);
		}
		return userNum;
	}

	public List<Tuser> getUserPagination(Map<String, Object> params, Map<String, String> conditions, int page, int rows) {
		List<Tuser> users = new ArrayList<Tuser>();
		Map<String, Object> vparams = new HashMap<String, Object>();
		String hql = "select u from Tuser u, SysRoles sr, SysRoleMembers srm ";
		String condition = "";
		boolean searchExt = false;
		if (null != params && params.size() > 0) {
			for (String key : params.keySet()) {
				String valueKey = key.substring(key.indexOf(".") + 1);
				condition += " and " + key + " " + conditions.get(key) + ":" + valueKey;
				vparams.put(valueKey, params.get(key));
				// 有扩展信息查询
				if (!searchExt && key.indexOf("ue.") > -1) {
					hql += ", UserExtend ue";
					searchExt = true;
				}
			}
			hql += " where 1=1 and srm.memberid=u.id and srm.sysRoles=sr.id";
			if (searchExt) {
				condition += " and u.id = ue.tuser";
			}
			hql += condition + " and u.name <> 'admin' order by userState, createDate";
			users = userDao.find(hql, vparams, page, rows);
		} else {
			hql += " where u.name <> 'admin' and srm.memberid=u.id and srm.sysRoles=sr.id order by userState, createDate";
			users = userDao.find(hql, page, rows);
		}

		return users;
	}
	
	public List<TreeNode> getCompanyTree(Puser user) {
		List<TreeNode> tree = new ArrayList<TreeNode>();
		String hql = "select u from Tuser u, SysRoles sr, SysRoleMembers srm where u.userType=:userType and srm.type=:type and sr.roleName=:roleName and u.parentid=:parentid and u.name <> 'admin' and srm.memberid=u.id and srm.sysRoles=sr.id order by userState, createDate";
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("userType", Constant.USERTYPE_COMPANY);
		params.put("type", Constant.SYSROLE_MEMBER_TYPE_USER);
		params.put("roleName", "企业数据员");
		params.put("parentid", user.getId());
		
		List<Tuser> users = userDao.find(hql, params);
		if(null != users && users.size() > 0) {
			TreeNode root = new TreeNode();
			List<TreeNode> nodes = new ArrayList<TreeNode>();
			root.setId(user.getId());
			root.setText(user.getName());
			root.setChildren(nodes);
			for(Tuser u : users) {
				TreeNode tn = new TreeNode();
				tn.setId(u.getId());
				tn.setText(u.getName());
				nodes.add(tn);
			}
			tree.add(root);
		}
		
		return tree;
	}

	public void updateUserInfo(Puser puser) {
		Tuser user = getUserById(puser.getId());
		UserExtend ux = user.getUserExtends().iterator().next();
		BeanUtils.copyProperties(puser, user);
		BeanUtils.copyProperties(puser.getPuserExtend(), ux);
		userDao.update(user);

		setUser(user);
	}

	public void updateUserInfo(Tuser tuser) {
		userDao.update(tuser);

		setUser(tuser);
	}

	public void saveOrUpdateExtend(UserExtend userExtend) {
		extendDao.saveOrUpdate(userExtend);
	}

	public Puser login(Puser user) {
		Tuser tuser = getUserByName(user.getName());
		if (null != tuser && tuser.getPwd().equals(StringUtils.encrypt(user.getPwd()))) {
			BeanUtils.copyProperties(tuser, user);
			Set<UserExtend> ues = tuser.getUserExtends();
			if (null != ues && ues.size() > 0) {
				BeanUtils.copyProperties(ues.iterator().next(), user.getPuserExtend());
			}
			return user;
		}
		return null;
	}

	public Map<String, Object> getUserItemByName(Puser user) {
		Map<String, Object> valueMap = new LinkedHashMap<String, Object>();

		String hql = "from Tuser where name=:name or displayName like:displayName";
		String countHql = "select count(*) from Tuser where name=:name or displayName like:displayName";
		Map<String, Object> params = new LinkedHashMap<String, Object>();
		params.put("name", user.getDisplayName());
		params.put("displayName", "%" + user.getDisplayName() + "%");
		List<Tuser> users = userDao.find(hql, params);
		Long total = userDao.getCount(countHql, params);

		List<Puser> pusers = new ArrayList<Puser>();
		if (null != users && users.size() > 0) {
			for (Tuser tu : users) {
				Puser puser = new Puser();
				BeanUtils.copyProperties(tu, puser);
				pusers.add(puser);
			}
		}
		valueMap.put("total", total);
		valueMap.put("rows", pusers);

		return valueMap;
	}

	public List<Tuser> getAllUser() {
		return getAllUser(false);
	}

	public List<Tuser> getAllUser(boolean isInit) {
		List<Tuser> ls = new ArrayList<Tuser>();
		if (isInit || Constant.GET_USER_FROM_DB) {
			ls = userDao.find("from Tuser order by name desc, userState desc");
		} else {
			ls = new ArrayList<Tuser>(Constant.USER_ID_KEY_MAP.values());
		}

		return ls;
	}

	public Tuser getUserById(String id) {
		if (Constant.GET_USER_FROM_DB) {
			Map<String, Object> params = new LinkedHashMap<String, Object>();
			params.put("id", id);
			return userDao.get("from Tuser where id=:id", params);
		} else {
			return Constant.USER_ID_KEY_MAP.get(id);
		}
	}

	public Tuser getUserByName(String name) {
		if (Constant.GET_USER_FROM_DB) {
			Map<String, Object> params = new LinkedHashMap<String, Object>();
			params.put("name", name);
			return userDao.get("from Tuser where name=:name", params);
		} else {
			return Constant.USER_NAME_KEY_MAP.get(name);
		}
	}

	public void setUser(Tuser user) {
		if (!Constant.GET_USER_FROM_DB) {
			// 内存中无此用户，则加进去
			if (null == Constant.USER_NAME_KEY_MAP.get(user.getName())) {
				Constant.USER_ID_KEY_MAP.put(user.getId(), user);
				Constant.USER_NAME_KEY_MAP.put(user.getName(), user);
			}
		}
	}

	public void initUserMap() {
		logger.info("加载用户...");
		List<Tuser> users = getAllUser(true);
		Constant.USER_ID_KEY_MAP = new LinkedHashMap<String, Tuser>();
		Constant.USER_NAME_KEY_MAP = new LinkedHashMap<String, Tuser>();
		for (Tuser user : users) {
			setUser(user);
		}
	}

}
